'use strict';

var utils = require('./utils');
var bind = require('./helpers/bind');
var Axios = require('./core/Axios');
var mergeConfig = require('./core/mergeConfig');
var defaults = require('./defaults');

/**
 * Create an instance of Axios
 *
 * @param {Object} defaultConfig The default config for the instance
 * @return {Axios} A new instance of Axios
 */
function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  // 注意，返回的是绑定之后的request方法，而不是Axios实例
  var instance = bind(Axios.prototype.request, context);

  // Copy axios.prototype to instance
  // 将Axios.prototype原型上的方法添加到instance对象上，如果原型上存在函数，
  // 则绑定该函数的执行上下文是context后，添加到instance对象上。
  utils.extend(instance, Axios.prototype, context);

  // Copy context to instance
  // 将Axios实例的特有属性与方法添加到instance对象上
  utils.extend(instance, context);

  return instance;
}

// Create the default instance to be exported
// 该实例作为默认实例，会在所有新创建的实例上共享选项
var axios = createInstance(defaults);

// Expose Axios class to allow class inheritance
axios.Axios = Axios;

// Factory for creating new instances
axios.create = function create(instanceConfig) {
  // 全局单例实例axios的选项defaults会在每个新创建的实例上共享，
  // 所以可以在axios.defaults设置共享的选项
  // 所以分三种优先级的配置对象：
  // 1）初始化创建的默认axios实例的配置对象，也就是defaults对象
  // 2）通过当前create方法创建新的axios实例时，可以提供配置对象，也就是该方法的第一个参数instanceConfig
  // 3）对于axios实例上的request方法，在调用时，也可以再次指定配置对象。
  // 而配置对象的优先级从下往上的，也就是3）、2）、1），选项的具体合并策略，可查看mergeConfig方法
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

// Expose Cancel & CancelToken
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');

// Expose all/spread
axios.all = function all(promises) {
  return Promise.all(promises);
};
axios.spread = require('./helpers/spread');

module.exports = axios;

// Allow use of default import syntax in TypeScript
module.exports.default = axios;
